package com.ruoyi.common.utils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.*;

import org.apache.commons.lang3.time.DateFormatUtils;

/**
 * 时间工具类
 *
 * @author ruoyi
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }


    /**
     * 计算两个时间差
     */
    public static long getDateCount(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        return day;
    }

    public static LocalDate dateAfterToday(int days) {
        return LocalDate.now().plusDays(days);
    }

    /**
     * 获取明天的日期字符串
     *
     * @return
     */
    public static Date tomorrowDate() {
        Date date = new Date();//取时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //把日期往后增加一天.整数往后推,负数往前移动(1:表示明天、-1：表示昨天，0：表示今天)
        calendar.add(Calendar.DATE, 1);
        //这个时间就是日期往后推一天的结果
        date = calendar.getTime();
        return date;
    }


    /**
     * 获取两个时间之间的日期（包括结束日期）
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<Date> getDatesBetweenUsingJava7(Date startDate, Date endDate) {
        List<Date> datesInRange = new ArrayList<Date>();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(startDate);
        Calendar endCalendar = new GregorianCalendar();
        endCalendar.setTime(endDate);
        //推后一天
        endCalendar.add(Calendar.DATE, 1);
        while (calendar.before(endCalendar)) {
            Date result = calendar.getTime();
            datesInRange.add(result);
            calendar.add(Calendar.DATE, 1);
        }
        return datesInRange;
    }

    /**
     * 获取两个时间之间的日期（包括结束日期）
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<String> getDatesBetweenUsingJava7String(Date startDate, Date endDate) {
        List<String> datesInRange = new ArrayList<>();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(startDate);
        Calendar endCalendar = new GregorianCalendar();
        endCalendar.setTime(endDate);
        //推后一天
        endCalendar.add(Calendar.DATE, 1);
        while (calendar.before(endCalendar)) {
            Date result = calendar.getTime();
            datesInRange.add(parseDateToStr(DateUtils.YYYY_MM_DD, result));
            calendar.add(Calendar.DATE, 1);
        }
        return datesInRange;
    }


    /**
     * 输入一个日期字符串获取Date当天开始时间
     * @param dateString
     * @return
     */
    public static  Date getDateBegin(String dateString) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
              date = dateFormat.parse(dateString);
            System.out.println(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 输入一个日期字符串获取当天结束时间
     * @param dateString
     * @return
     */
    public static  Date getDateEnd(String dateString) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date newDate = null;
        try {
            Date date = dateFormat.parse(dateString);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            newDate = calendar.getTime();
            System.out.println(newDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return newDate;
    }

    /**
     * 获取当前日期及当前日期前dayNum天之间的日期字符串数组
     * @param dayNum
     * @return
     */
    public static String[] getDateList(int dayNum) {
        String[] dateList = new String[dayNum];
        for (int i = 0; i < dayNum; i++) {
            dateList[i] = dateAfterToday(-(dayNum - 1 - i)).toString();
        }
        return dateList;
    }


    /**
     * Date转为LocalDate
     * @param date
     * @return
     */
        public static LocalDate dateToLocalDate(Date date) {
            // 将Date转换为Instant
            Instant instant = date.toInstant();
            // 将Instant转换为LocalDate，使用系统默认时区
            LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
            // 输出LocalDate
            System.out.println(localDate);
            return  localDate;
        }


    /**
     * 输入一个结束日期获取这个日期之前num几天到这个日期结束时间段内所有的日期
     * @param endDate
     * @return
     */
    public static String[] getDateRange (Date endDate, int num) {
        // 设定结束日期
        LocalDate endTime = dateToLocalDate(endDate);
        // 计算前7天的日期范围
        LocalDate startDate = endTime.minusDays(num);
        // 创建日期列表
        List<String> dateList = new ArrayList<>();
        // 循环遍历日期范围，将日期字符串添加到列表中
        for (LocalDate date = startDate; !date.isAfter(endTime); date = date.plusDays(1)) {
            dateList.add(date.toString());
        }
        // 输出日期字符串数组
        for (String dateStr : dateList) {
            System.out.println(dateStr);
        }
        return dateList.toArray(new String[dateList.size()]);
    }




    /**
     * 获取当前日期
     * @return
     */
    public static Date getCurrentDate() {
        final Date date = new Date();
        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        final String workDate = sdf.format(date);
        Date date1 = null;
        try {
            date1 = sdf.parse(workDate);
        } catch (final ParseException e) {
            e.printStackTrace();
        }
        return date1;
    }

    /**
     * 获取当前时间
     * @return
     */
    public static Date getCurrentTime() {
        Date date = new Date();
        return date;
    }


    /**
     * 补全日期
     *
     * @param begin
     * @param end
     * @param pattern
     * @param data
     * @param dateKey
     * @param dataKey
     */
    public static void fixMonth(String begin, String end, String pattern, List<Map<String, Object>> data, String dateKey, String dataKey) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD);
        LocalDate beginDate = LocalDate.parse(begin, formatter);
        LocalDate endDate = LocalDate.parse(end, formatter);
        long month = ChronoUnit.MONTHS.between(beginDate, endDate);
        if (month > 0) {
            String date;
            Map<String, Object> map;
            List<Map<String, Object>> fix = new ArrayList<Map<String, Object>>();
            boolean find;
            for (long i = 0; i < month; i++) {
                date = beginDate.plus(i, ChronoUnit.MONTHS).format(DateTimeFormatter.ofPattern(pattern));
                find = false;
                for (Map<String, Object> temp : data) {
                    if (StringUtils.equals((String) temp.get(dateKey), date)) {
                        find = true;
                        break;
                    }
                }
                if (!find) {
                    map = new HashMap<>();
                    map.put(dateKey, date);
                    map.put(dataKey, 0);
                    fix.add(map);
                }
            }
            data.addAll(fix);
            Collections.sort(data, new MapComparatorDesc());
        }
    }


    public static class MapComparatorDesc implements Comparator<Map<String, Object>> {
        @Override
        public int compare(Map<String, Object> m1, Map<String, Object> m2) {
            String v1 = (String) m1.get("datetime");
            String v2 = (String) m2.get("datetime");

            LocalDate beginDate = toLocalDate(v1, YYYY_MM);
            LocalDate endDate = toLocalDate(v2, YYYY_MM);

            if (endDate != null) {
                return endDate.compareTo(beginDate);
            }
            return 0;
        }
    }


    public static LocalDate toLocalDate(String datetime, String pattern) {
        DateTimeFormatter smartFormatter = new DateTimeFormatterBuilder().appendPattern(pattern)
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1).parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
                .parseDefaulting(ChronoField.NANO_OF_SECOND, 0).toFormatter();
        return LocalDate.parse(datetime, smartFormatter);
    }


    /**
     * @param timeType
     * @param beginPublishDay 2021-08-01
     * @param endPublishDay   2021-08-02
     * @return
     */
    public static HashMap<String, Object> getStartEndTime(String timeType, String beginPublishDay, String endPublishDay) {
        String currDate = DateUtils.dateAfterToday(0).toString();
        int dayNum = 0;
        if (timeType != null) {
            if (timeType.equals("today")) {
                beginPublishDay = DateUtils.dateAfterToday(0).toString();
                endPublishDay = currDate;
                dayNum = 1;
            } else if (timeType.equals("yesterday")) {
                beginPublishDay = DateUtils.dateAfterToday(-1).toString();
                endPublishDay = currDate;
                dayNum = 2;
            } else if (timeType.equals("week")) {
                beginPublishDay = DateUtils.dateAfterToday(-6).toString();
                endPublishDay = currDate;
                dayNum = 7;

            } else if (timeType.equals("month")) {
                beginPublishDay = DateUtils.dateAfterToday(-29).toString();
                endPublishDay = currDate;
                dayNum = 30;

            } else if (timeType.equals("define")) {
                dayNum = (int) DateUtils.getDateCount(DateUtils.parseDate(endPublishDay), DateUtils.parseDate(beginPublishDay));
            }

        }
        HashMap hashMap = new HashMap();
        hashMap.put("dayNum", dayNum);
        hashMap.put("beginPublishDay", beginPublishDay + " 00:00:00");
        hashMap.put("endPublishDay", endPublishDay + " 23:59:59");
        return hashMap;
    }

    public static Date LocalDateTimeToUdate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        Date date = Date.from(instant);
        return date;
    }

    // 05. java.time.LocalDate --> java.util.Date
    public static Date LocalDateToUdate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        Date date = Date.from(instant);
        return date;
    }

    /**
     * @param timeType
     * @param beginPublishDay 2021-08-01
     * @param endPublishDay   2021-08-02
     * @return
     */
    public static HashMap<String, Object> getStartEndTime(String timeType, Date beginPublishDay, Date endPublishDay) {
        //当日的结束时间
        Date currDate =  DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD , DateUtils.getCurrentDate())+" 23:59:59");
        int dayNum = 0;
        if (timeType != null) {
            if (timeType.equals("today")) {
                beginPublishDay = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(0));
                endPublishDay = currDate;
                dayNum = 1;
            } else if (timeType.equals("yesterday")) {
                beginPublishDay = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-1));
                endPublishDay = currDate;
                dayNum = 2;
            } else if (timeType.equals("week")) {
                beginPublishDay = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-6));
                endPublishDay = currDate;
                dayNum = 7;

            } else if (timeType.equals("month")) {
                beginPublishDay = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-29));
                endPublishDay = currDate;
                dayNum = 30;

            } else if (timeType.equals("all")) {
                //all默认取三个月的数据
                beginPublishDay = DateUtils.LocalDateToUdate(DateUtils.dateAfterToday(-89));
                endPublishDay = currDate;
                dayNum = 90;

            } else if (timeType.equals("define")) {
                dayNum = (int) DateUtils.getDateCount(endPublishDay, beginPublishDay);
            }

        }
        HashMap hashMap = new HashMap();
        hashMap.put("dayNum", dayNum);
        hashMap.put("beginPublishDay", beginPublishDay);
        hashMap.put("endPublishDay", endPublishDay);
        return hashMap;
    }

    public static String getZonedDateTimetoString(ZonedDateTime zonedDateTime, String format){
        ZonedDateTime zbj = zonedDateTime.now(); // 默认时区
        ZonedDateTime zoneDateTime1 = zonedDateTime.plusHours(11);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return zoneDateTime1.format(formatter);
    }

    public static String zonedDateTimeToString(ZonedDateTime zonedDateTime,String format){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format)
                .withZone(ZoneId.of("Asia/Shanghai"));
        if(zonedDateTime != null){
            return zonedDateTime.format(formatter);
        }
        return "";
    }



}
